﻿/* main.c */
#include "app.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

#define APP_NN_SAMPLE_GROUP_NUM       2
#define APP_NN_SAMPLE_GROUP_ELEM_NUM  100

/*******************************************************************************
 * Variables
 ******************************************************************************/

uint32_t tick_counter_val; /* 用于计时. */

nn_layer_t app_nn_layer1;
nn_layer_t app_nn_layer2;

float    app_nn_input[2];          /* layer1->n_input = 2. */
float    app_nn_layer1_output[10]; /* layer1->n_output = 10. */
float    app_nn_layer2_output[2];  /* layer1->n_output = 2. */
uint32_t app_nn_err;
float * app_nn_output;

/* samples. */
float   x0[APP_NN_SAMPLE_GROUP_NUM*APP_NN_SAMPLE_GROUP_ELEM_NUM];
float   x1[APP_NN_SAMPLE_GROUP_NUM*APP_NN_SAMPLE_GROUP_ELEM_NUM];
uint32_t y[APP_NN_SAMPLE_GROUP_NUM*APP_NN_SAMPLE_GROUP_ELEM_NUM];
uint32_t y_nn[APP_NN_SAMPLE_GROUP_NUM*APP_NN_SAMPLE_GROUP_ELEM_NUM];

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
void app_nn_init(void);
uint32_t app_nn_forward_2(float *input);
float * app_nn_forward_pq(float *input);
float * app_nn_forward_arm(float *input);

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Main function
 */
int main(void)
{
    BOARD_InitHardware();

    PRINTF("\r\nPowerQuad NN Examples.\r\n\r\n");

    /* 随机生成样本点.
     * group0的坐标在( 2,  2)附近.
     * group1的坐标在(-2, -2)附近.
     */
    srand(1); /* 初始化随机数发生器种子. */ /* rand() */
    for (uint32_t i = 0u; i < APP_NN_SAMPLE_GROUP_ELEM_NUM; i++)
    {
        /* group0. */
        x0[i] = 0.01f * (rand()%400);
        x1[i] = 0.01f * (rand()%400);
        y[i] = 0;
        /* group1. */
        x0[i + APP_NN_SAMPLE_GROUP_ELEM_NUM] = -0.01f * (rand()%400);
        x1[i + APP_NN_SAMPLE_GROUP_ELEM_NUM] = -0.01f * (rand()%400);
        y[i + APP_NN_SAMPLE_GROUP_ELEM_NUM] = 1;
    }

    app_nn_init();
    app_nn_err = 0;

    for (uint32_t i = 0u; i < APP_NN_SAMPLE_GROUP_ELEM_NUM * APP_NN_SAMPLE_GROUP_NUM; i++)
    {
        float max_val;
        app_nn_input[0] = x0[i];
        app_nn_input[1] = x1[i];

        TimerCount_Start(); /* 开始计时 */
        app_nn_output = app_nn_forward_arm(app_nn_input); /* 使用人工神经网络计算分类. */
        //app_nn_output = app_nn_forward_pq(app_nn_input); /* 使用人工神经网络计算分类. */
        TimerCount_Stop(tick_counter_val);

        arm_max_f32(app_nn_layer2_output, app_nn_layer2.n_output, &max_val, &y_nn[i]);

        if (y_nn[i] != y[i])
        {
            app_nn_err++; /* 统计错误数. */
        }
        PRINTF("[%3d]. (%9f, %9f): %d in %d us\r\n",i, x0[i], x1[i], y_nn[i], tick_counter_val/96);
    }

    PRINTF("app_nn_err: %d\r\n", app_nn_err);
    PRINTF("done.\r\n");

    while (1)
    {
    }
}

void app_nn_init(void)
{
    nn_init();

    nn_layer_init(&app_nn_layer1, 2, 10, nn_param_hidden_weight, nn_param_hidden_bias);
    nn_layer_init(&app_nn_layer2, 10, 2, nn_param_out_weight, nn_param_out_bias);
}

/* 直接返回标签值. */
uint32_t app_nn_forward_2(float *input)
{
    float max_val;
    uint32_t max_idx;

    nn_layer_forward_linear_arm(&app_nn_layer1, input, app_nn_layer1_output);
    nn_layer_activate_relu(app_nn_layer1_output, app_nn_layer1_output, app_nn_layer1.n_output);
    nn_layer_forward_linear_arm(&app_nn_layer2, app_nn_layer1_output, app_nn_layer2_output);

    arm_max_f32(app_nn_layer2_output, app_nn_layer2.n_output, &max_val, &max_idx);

    return max_idx;
}

float * app_nn_forward_pq(float *input)
{
    nn_layer_forward_linear_pq(&app_nn_layer1, input, app_nn_layer1_output);
    nn_layer_activate_relu(app_nn_layer1_output, app_nn_layer1_output, app_nn_layer1.n_output);
    nn_layer_forward_linear_pq(&app_nn_layer2, app_nn_layer1_output, app_nn_layer2_output);

    return app_nn_layer2_output;
}

float * app_nn_forward_arm(float *input)
{
    nn_layer_forward_linear_arm(&app_nn_layer1, input, app_nn_layer1_output);
    nn_layer_activate_relu(app_nn_layer1_output, app_nn_layer1_output, app_nn_layer1.n_output);
    nn_layer_forward_linear_arm(&app_nn_layer2, app_nn_layer1_output, app_nn_layer2_output);

    return app_nn_layer2_output;
}

/* EOF. */

